package com.jackrain.nea.core.service;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jackrain.nea.core.api.AdTableSaveCmd;
import com.jackrain.nea.core.entity.AdColumnModel;
import com.jackrain.nea.core.entity.AdTableModel;
import com.jackrain.nea.core.entity.AdTableSqlModel;
import com.jackrain.nea.core.mapper.*;
import com.jackrain.nea.core.utility.CommandData;
import com.jackrain.nea.exception.NDSException;
import com.jackrain.nea.sys.CommandAdapter;
import com.jackrain.nea.util.Tools;
import com.jackrain.nea.util.ValueHolder;
import com.jackrain.nea.web.face.User;
import com.jackrain.nea.web.query.QuerySession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Slf4j
@Component
@Service(protocol = "dubbo", validation = "true", version = "1.0", group = "ad")
public class AdTableSaveCmdImpl extends CommandAdapter implements AdTableSaveCmd {

    @Autowired
    private DirectoryMapper directoryMapper;
    @Autowired
    private AdRefbyTableAddCmdImpl adRefbyTableAddCmdImpl;

    @Autowired
    private MapperShortcut mapperShortcut;
    @Autowired
    private AdTableMapper adTableMapper;
    @Autowired
    private AdColumnMapper adColumnMapper;
    @Autowired
    private AdTableSqlMapper adTableSqlMapper;
    @Autowired
    private MapperDDL mapperDDL;

    private String getDDL(CommandData data, String pname) {
        AdTableModel table = adTableMapper.selectByTableName(pname);
        if (table == null) {
            return "\n";
        }

        StringBuffer v_ddl = new StringBuffer();

        v_ddl.append("CREATE TABLE " + pname + "(\n");

        long tableid = table.getId();
        List<AdColumnModel> list = adColumnMapper.selectByTableId(tableid);
        for (AdColumnModel column : list) {
            String dbname = column.getDbname();
            String coltype = column.getColtype();
            String nullable = column.getNullable();
            String defaultvalue = column.getDefaultvalue();


            if (!data.checkVirtual(dbname)) {

                if (coltype.equals("DATETIME")) {
                    v_ddl.append(" " + dbname + " " + data.convertmysqltype("DATE") + " ");
                } else if (coltype.equals("DATENUMBER")) {
                    v_ddl.append(" " + dbname + " " + data.convertmysqltype("NUMBER(8)") + " ");
                } else {
                    v_ddl.append(" " + dbname + " " + data.convertmysqltype(coltype));
                }


                if (defaultvalue != null) {
                    if (defaultvalue.indexOf("=") < 0 && defaultvalue.indexOf("$") < 0) {
                        if (coltype.indexOf("NUM") > 0) {
                            v_ddl.append(" DEFAULT " + defaultvalue);
                        } else if (coltype.indexOf("DATE") > 0) {
                            v_ddl.append(" DEFAULT NULL");
                        } else {
                            v_ddl.append(" DEFAULT '" + defaultvalue + "'");
                        }
                    }
                }


                if (nullable.equals("N")) {
                    v_ddl.append(" NOT NULL");
                }
                v_ddl.append(",\n");
            }
        }
        String pkColumnName = adColumnMapper.selectDbNameByTableid(Tools.getLong(table.getPkColumnId(), -1));

        v_ddl.append("    PRIMARY KEY (" + pkColumnName + ")");


        //index for ak and status
        //UNIQUE KEY AKM_PRODUCT (NAME,AD_CLIENT_ID)

        String akcolname = adColumnMapper.selectDbNameByTableid(Tools.getLong(table.getAkColumnId(), -1));

        if (!akcolname.equals("ID")) {
            v_ddl.append(",\n");

            if (adTableMapper.columnCount(pname, "AD_CLIENT_ID") == 0) {
                v_ddl.append("UNIQUE KEY AK" + pname + " (" + akcolname + ")\n");
            } else {
                v_ddl.append("UNIQUE KEY AK" + pname + " (" + akcolname + ",AD_CLIENT_ID)\n");
            }
        }

        //--status index
        if (adTableMapper.columnCount(pname, "STATUS") > 0) {
            v_ddl.append("UNIQUE KEY IX_" + pname + "_01 (status)\n");
        }
        return v_ddl.append(");\n").toString();
    }


    @Override
    @Transactional
    public ValueHolder execute(QuerySession session) throws NDSException {
        CommandData data = new CommandData(session);

        if (!data.isModifying()) {
            throw data.notSupported();
        }


        JSONArray jar = data.getItemData("AD_REFBYTABLE", false);


        if (jar != null && !jar.isEmpty()) {
            return adRefbyTableAddCmdImpl.execute(session);

        }

        User user = session.getUser();
        int userid = user.getId();

        long tableId = data.getObjId();
        JSONObject table = data.getMainData("AD_TABLE", true);

        if (table.containsKey("MASK")) {
            String v_mask = table.getString("MASK").trim().toUpperCase();
            //check mask
            if (!v_mask.matches("[AMDSQPGUVB]+")) {
                throw data.exception("Table mask must be in 'AMDSQPGUVB', input is:", v_mask);
            }
            // 如果包含批量修改(B) 但不包括修改(M) 则抛出异常
            if (v_mask.contains("B") && !v_mask.contains("M")) {
                throw data.exception("If the table mask existed 'B' Then must be exists 'M'");
            }
        }

        table.put("ID", tableId);
        if (table.containsKey("NAME")) {
            return data.error(-1, "表名", "不能修改");
        }
        data.setUpdateDefaultValue(table);
        int affect = mapperShortcut.update(table, "AD_TABLE"); //更新实体

        //获取参数
        long parent_tableid = Tools.getLong(table.getLong("PARENT_TABLE_ID"), -1);
        String v_istree = Tools.nvl(table.getString("ISTREE"), "N");
        long v_summary_column_id = Tools.getLong(table.getLong("SUMMARY_COLUMN_ID"), -1);


        // 同步目录的描述和表的描述一致
        directoryMapper.syncTableDescription(tableId);
        directoryMapper.syncAdTableCategoryId(tableId);

        /*
         * -- 如果为树型结构，必须设置parent_column_id 和 summary_column_id --
         * parent_column_id 必须FK指向本表PK, -- summary_column_id 必须是YESNO 型
         */
        long v_pk_column_id = Tools.getLong(adTableMapper.pkColumnId(tableId), -1);
        if (v_istree.equals("Y")) {
            if (v_summary_column_id < 0 || parent_tableid < 0) {
                throw data.exception("必须设置汇总标识字段和父节点字段");
            }
            long v_ref_column_id = Tools.getLong(adColumnMapper.refColumnId(tableId), -1);
            if (v_ref_column_id < 0 || v_ref_column_id != v_pk_column_id) {
                throw data.exception("必须设置汇总标识字段和父节点字段");
            }

            /* -- summary_column_id 必须是YESNO 型 */
            int count = adColumnMapper.columnCountWithYesNoGroup(v_summary_column_id);
            if (count == 0) {
                throw data.exception("汇总标识字段字段应该是选项型(YESNO)");
            }
        }

        JSONObject model = data.getItemSingle("AD_TABLESQL", false);
        long sqlId = model.getLongValue("ID");

        if (sqlId > 0) {
            data.setUpdateDefaultValue(model);
            mapperShortcut.update(model, "AD_TABLESQL");

            //获取参数
            // sqlaction [ M=先删除并后创建 R=据当前定义创建DDL C=执行创建语句内容 D=执行删除语句内容 B=更名到备份表]
            String sqlaction = model.getString("SQLACTION");
            String tabname = table.containsKey("NAME") ? table.getString("NAME") : adTableMapper.selectNameById(tableId);


            if (sqlaction == null) {
                return data.success();
            }

            if (sqlaction.equals("B")) {
                String vsql = "alter table " + tabname + " rename to " + tabname + "_log";
                adTableSqlMapper.DDLLog(tableId, vsql);

                try {
                    mapperDDL.exec(vsql);
                } catch (Exception e) {
                    log.debug("备份表失败", e);
                    throw new NDSException(tabname + "对应的备份表,已存在!");
                }
            } else if (sqlaction.equals("R")) {
                String ddl = getDDL(data, tabname);
                adTableSqlMapper.updateCreateAndDrop(sqlId, ddl, "DROP TABLE " + tabname + ";");
            } else if (sqlaction.equals("M")) {
                AdTableSqlModel tabelSql = adTableSqlMapper.select(sqlId);
                String sql_drop = tabelSql.getSqlDrop();
                String sql_create = tabelSql.getSqlCreate();

                try {
                    mapperDDL.exec(sql_drop);
                } catch (Exception e) {
                    log.debug("表删除失败1", e);
                    //throw new NDSEventException(tabname+"表删除失败,不存在!");
                }
                try {
                    mapperDDL.exec(sql_create);
                } catch (Exception e) {
                    log.debug("表创建失败1", e);
                    throw data.exception(tabname, "表创建失败,已存在!");
                }
            } else if (sqlaction.equals("D")) {
                String sql_drop = adTableSqlMapper.sqlDrop(sqlId);
                try {
                    mapperDDL.exec(sql_drop);
                } catch (Exception e) {
                    log.debug("表删除失败2", e);
                    throw data.exception(tabname, "表删除失败,不存在!");
                }
                adTableSqlMapper.updateSqlLog2Null(sqlId);
            } else if (sqlaction.equals("C")) {
                String sql_create = adTableSqlMapper.sqlCreate(sqlId);
                try {
                    mapperDDL.exec(sql_create);
                } catch (Exception e) {
                    log.debug("表创建失败2", e);
                    throw data.exception(tabname, "表创建失败,已存在!");
                }
                adTableSqlMapper.updateSqlLog2Null(sqlId);
            }

            adTableSqlMapper.updateSqlAction2Null(sqlId);
        }

        return data.success();
    }
}
